package com.nanhai.buddhist.college.module.collegebase.service.accommodationbuilding;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nanhai.buddhist.college.framework.common.pojo.PageResult;
import com.nanhai.buddhist.college.framework.common.util.collection.CollectionUtils;
import com.nanhai.buddhist.college.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.accommodationbuilding.vo.AccommodationBuildingCreateReqVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.accommodationbuilding.vo.AccommodationBuildingExportReqVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.accommodationbuilding.vo.AccommodationBuildingPageReqVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.accommodationbuilding.vo.AccommodationBuildingUpdateReqVO;
import com.nanhai.buddhist.college.module.collegebase.convert.accommodationbuilding.AccommodationBuildingConvert;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.accommodationbed.AccommodationBedDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.accommodationbuilding.AccommodationBuildingDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.accommodationfloor.AccommodationFloorDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.accommodationreside.AccommodationResideDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.accommodationroom.AccommodationRoomDO;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.accommodationbed.AccommodationBedMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.accommodationbuilding.AccommodationBuildingMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.accommodationfloor.AccommodationFloorMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.accommodationreside.AccommodationResideMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.accommodationroom.AccommodationRoomMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.nanhai.buddhist.college.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.nanhai.buddhist.college.module.collegebase.enums.ErrorCodeConstants.ACCOMMODATION_BUILDING_NOT_DELETE;
import static com.nanhai.buddhist.college.module.collegebase.enums.ErrorCodeConstants.ACCOMMODATION_BUILDING_NOT_EXISTS;

/**
 * 楼栋管理 Service 实现类
 *
 * @author AKai
 */
@Service
@Validated
public class AccommodationBuildingServiceImpl implements AccommodationBuildingService {

    @Resource
    private AccommodationBuildingMapper accommodationBuildingMapper;

    @Resource
    private AccommodationFloorMapper accommodationFloorMapper;

    @Resource
    private AccommodationRoomMapper accommodationRoomMapper;

    @Resource
    private AccommodationBedMapper accommodationBedMapper;

    @Resource
    private AccommodationResideMapper accommodationResideMapper;

    @Override
    @Transactional
    public String createAccommodationBuilding(AccommodationBuildingCreateReqVO createReqVO) {
        // 插入
        AccommodationBuildingDO accommodationBuilding = AccommodationBuildingConvert.INSTANCE.convert(createReqVO);


        accommodationBuildingMapper.insert(accommodationBuilding);
        addFloorDO(createReqVO.getFloorConfig(), accommodationBuilding.getId());

        // 返回
        return accommodationBuilding.getId();
    }

    private void addFloorDO(String floorConfig, String accommodationBuildingId) {
        if (StringUtils.isBlank(floorConfig) || StringUtils.isBlank(accommodationBuildingId)) {
            return;
        }

        if (StringUtils.isNumeric(floorConfig)) {
            int num = Integer.parseInt(floorConfig);
            for (int i = 1; i <= num; i++) {
                AccommodationFloorDO floorDO = new AccommodationFloorDO();
                floorDO.setBuildingId(accommodationBuildingId);
                floorDO.setFloorName("第" + i + "层");
                accommodationFloorMapper.insert(floorDO);
            }
        } else {
            AccommodationFloorDO floorDO = new AccommodationFloorDO();
            floorDO.setBuildingId(accommodationBuildingId);
            floorDO.setFloorName(floorConfig);
            accommodationFloorMapper.insert(floorDO);
        }


    }

    @Override
    @Transactional
    public void updateAccommodationBuilding(AccommodationBuildingUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateAccommodationBuildingExists(updateReqVO.getId());
        // 更新
        AccommodationBuildingDO updateObj = AccommodationBuildingConvert.INSTANCE.convert(updateReqVO);
        accommodationBuildingMapper.updateById(updateObj);

        // 同步更新楼层
        if (StringUtils.isNoneBlank(updateReqVO.getFloorConfig())) {
            deleteFloorDO(updateReqVO.getId());
            addFloorDO(updateReqVO.getFloorConfig(), updateReqVO.getId());
        }

    }

    @Override
    @Transactional
    public void deleteAccommodationBuilding(String id) {
        // 校验存在
        this.validateAccommodationBuildingExists(id);


        List<AccommodationFloorDO> accommodationFloorDOS = accommodationFloorMapper.selectList(AccommodationFloorDO::getBuildingId, id);


        // 有房间不能删除楼栋

        Long accommodationRoomDOS = accommodationRoomMapper.selectCount(new LambdaQueryWrapper<AccommodationRoomDO>().in(AccommodationRoomDO::getFloorId, CollectionUtils.convertSet(accommodationFloorDOS, AccommodationFloorDO::getId)));
        if (accommodationRoomDOS > 0) {
            throw exception(ACCOMMODATION_BUILDING_NOT_DELETE);
        }
        // 删除
        accommodationBuildingMapper.deleteById(id);
        accommodationRoomMapper.deleteBatchIds(CollectionUtils.convertSet(accommodationFloorDOS, AccommodationFloorDO::getId));
        deleteFloorDO(id);
    }

    private void deleteFloorDO(String id) {

        final List<AccommodationFloorDO> floorDOS = accommodationFloorMapper.selectList(new LambdaQueryWrapper<AccommodationFloorDO>().eq(AccommodationFloorDO::getBuildingId, id));
        if (CollectionUtil.isEmpty(floorDOS)) {
            // 没有楼层信息 直接返回，不进行下面操作
            return;
        }
        List<String> floorIds = floorDOS.stream().map(AccommodationFloorDO::getId).collect(Collectors.toList());
        // 删除楼层
        accommodationFloorMapper.deleteBatchIds(floorIds);
        final List<AccommodationRoomDO> roomDOs = accommodationRoomMapper.selectList(new LambdaQueryWrapper<AccommodationRoomDO>().in(AccommodationRoomDO::getFloorId, floorIds));
        if (CollectionUtil.isEmpty(roomDOs)) {
            // 没有房屋信息 直接返回，不进行下面操作
            return;
        }
        final List<String> roomIds = roomDOs.stream().map(AccommodationRoomDO::getId).collect(Collectors.toList());
        // 删除房屋
        accommodationRoomMapper.deleteBatchIds(roomIds);
        final List<AccommodationBedDO> bedDOS = accommodationBedMapper.selectList(new LambdaQueryWrapperX<AccommodationBedDO>().in(AccommodationBedDO::getRoomId, roomIds));
        if (CollectionUtil.isEmpty(bedDOS)) {
            // 没有床铺信息 直接返回，不进行下面操作
            return;
        }
        final List<String> bedIds = bedDOS.stream().map(AccommodationBedDO::getId).collect(Collectors.toList());
        // 删除床铺
        accommodationBedMapper.deleteBatchIds(bedIds);
        // 删除入住记录
        accommodationResideMapper.delete(new LambdaQueryWrapper<AccommodationResideDO>().in(AccommodationResideDO::getBedId, bedIds));
    }

    private void validateAccommodationBuildingExists(String id) {
        if (accommodationBuildingMapper.selectById(id) == null) {
            throw exception(ACCOMMODATION_BUILDING_NOT_EXISTS);
        }
    }

    @Override
    public AccommodationBuildingDO getAccommodationBuilding(String id) {
        return accommodationBuildingMapper.selectById(id);
    }

    @Override
    public List<AccommodationBuildingDO> getAccommodationBuildingList(Collection<String> ids) {
        return CollectionUtils.isEmpty(ids) ? Collections.emptyList() : accommodationBuildingMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<AccommodationBuildingDO> getAccommodationBuildingPage(AccommodationBuildingPageReqVO pageReqVO) {
        return accommodationBuildingMapper.selectPage(pageReqVO);
    }

    @Override
    public List<AccommodationBuildingDO> getAccommodationBuildingList(AccommodationBuildingExportReqVO exportReqVO) {
        return accommodationBuildingMapper.selectList(exportReqVO);
    }

}
